<!DOCTYPE html>
<html>
<head>
    <title></title>
    <link rel="stylesheet" type="text/css" href="../index.css">
    <style type="text/css">
        .animate-box {
            width: 600px;
            height: 300px;
            background: skyblue;
            margin: 50px auto 0;
            position: relative;
        }

        .ball, .ball-1 {
            width: 60px;
            height: 60px;
            border-radius: 50%;
            background-color: orange;
            position: absolute;
            left: 0;
            top: 0;
        }
    </style>
</head>
<body>
<div class="container">
    <h3>命令模式</h3>
    <div class="btns">
        <span id="btn1" class="span-click-btn">点击按钮1</span>
        <span id="btn2" class="span-click-btn">点击按钮2</span>
        <span id="btn3" class="span-click-btn">点击按钮3</span>
    </div>
    <div class="animate-box">
        <span class="ball"></span>
    </div>
    请输入移动位置： <input type="number" min="0" step="10" max="540" class="ipt-pos"><br>
    <span id="btn4" class="span-click-btn">开始运动</span>
    <span id="btn5" class="span-click-btn">撤销小球上次运动</span>
    <div class="cancal-opts" style="height: 240px; background: rgba(0,0,0,.3); color: #666;"></div>
    <span id="btn6" class="span-click-btn">撤销所有操作</span>
    <span id="btn7" class="span-click-btn">重新播放</span>
    <br>
    <br>
    <div class="animate-box">
        <span class="ball-1"></span>
    </div>
    <span id="btn8" class="span-click-btn">多次点击按顺序执行</span>
</div>
<script type="text/javascript" src="ball-move.js"></script>
<script type="text/javascript">
    (function() {

        // 传统面向对象编程的 命令模式
        // 将过程的（MenuBar, subMenu）请求调用封装在command对象（RefreshBarCommand, addSubMenuCommand）中
        // 命令对象已相同的方法 执行不通的过程
        // 在不同的指令对象上用相同的方法名，绑定不同的调用操作，然后给不同操作的按钮绑定不同指令，当用户点击时，指令对象调用不同的执行者

        /*var btn1 = document.getElementById('btn1');
        var btn2 = document.getElementById('btn2');
        var btn3 = document.getElementById('btn3');

        var setCommand = function(button, command) {
            button.onclick = function() {
                command.execute()
            }
        }
        // 命令的执行者
        var MenuBar = {
            refresh: function() {
                console.log('刷新了菜单')
            }
        }
        var subMenu = {
            add: function() {
                console.log('添加菜单')
            },
            del: function() {
                console.log('删除菜单')
            }
        }
        // 命令对象
        var RefreshMenuBarCommand = function(receiver) {
            this.receiver = receiver;
        }
        RefreshMenuBarCommand.prototype.execute = function() {
            this.receiver.refresh()
        }
        var addSubMenuCommand = function(receiver){
            this.receiver = receiver;
        }
        addSubMenuCommand.prototype.execute = function() {
            this.receiver.add()
        }
        var delSubMenuCommand = function(receiver) {
            this.receiver = receiver
        }
        delSubMenuCommand.prototype.execute = function() {
            this.receiver.del()
        }
        setCommand(btn1, new RefreshMenuBarCommand(MenuBar));
        setCommand(btn2, new addSubMenuCommand(subMenu));
        setCommand(btn3, new delSubMenuCommand(subMenu));*/


        // javascript 中的命令模式
        // 上述中引入command对象与receiver这两个角色看起来把简单的事情变复杂了
        /*var btn1 = document.getElementById('btn1');
        var btn2 = document.getElementById('btn2');
        var btn3 = document.getElementById('btn3');
        var bindClick = function(button, func) {
            button.onclick = func;
        }

        var MenuBar = {
            refresh: function() {
                console.log('刷新')
            }
        }

        var SubMenu = {
            add: function() {
                console.log('添加')
            },
            del: function() {
                console.log('删除')
            }
        }

        bindClick(btn1, MenuBar.refresh)
        bindClick(btn2, SubMenu.add)
        bindClick(btn3, SubMenu.del)*/


        // 添加撤销命令
        // 使用策略模式中的小球运动方法
        /*var ball = document.querySelector('.ball');
        var posIpt = document.querySelector('.ipt-pos');
        var moveBtn = document.getElementById('btn4');
        var cancalBtn = document.getElementById('btn5');


        // moveBtn.onclick = function() {
        // 	var animate = new Animate(ball);
        // 	animate.start('left', posIpt.value, 1000, 'Quart_easeInOut');
        // }

        // 修改为命令模式 并添加测绘
        var moveCommand;
        var MoveCommand = function(receiver, pos) {
            this.receiver = receiver;
            this.pos = pos;
            this.oldPos = null;
        }

        MoveCommand.prototype.execute = function() {
            this.receiver.start('left', this.pos, 1000, 'Quart_easeInOut');
            this.oldPos = this.receiver.startPos
        }

        MoveCommand.prototype.undo = function() {
            this.receiver.start('left', this.oldPos, 1000, 'Quart_easeInOut');
        }


        moveBtn.onclick = function() {
            var animate = new Animate(ball);
            moveCommand = new MoveCommand(animate, posIpt.value);
            moveCommand.execute();
        }

        cancalBtn.onclick = function() {
            moveCommand.undo();
        }*/

        // 撤销与重做
        // 将执行过的命令存储在一个历史列表中，当撤销到某个位置，再一次执行那个命令即可
        // 如 当按下一些指定按钮进行一些操作
        /*var cancalOpts = document.querySelector('#btn6');
        var replayBtn = document.querySelector('#btn7');
        var RyuBox = document.querySelector('.cancal-opts');
            var Ryu = {
                attack: function() {
                    console.log('攻击');
                    RyuBox.innerText = '攻击';
                },
                defense: function() {
                    console.log('防御');
                    RyuBox.innerText = '防御';
                },
                jump: function() {
                    console.log('跳跃');
                    RyuBox.innerText = '跳跃';
                },
                crouch: function() {
                    console.log('蹲下');
                    RyuBox.innerText = '蹲下';
                }
            }

            var makeCommand = function(receiver, state) {
                return function(){
                    receiver[state]()
                }
            }

            var commandKeys = {
                '119': 'jump',
                '115': 'crouch',
                '97': 'defense',
                '100': 'attack'
            }

            var commandStack = [];

            document.onkeypress = function(ev) {
                var keycode = ev.keyCode,
                    command = null,
                    action = commandKeys[keycode + ''];
                if(!action) {
                    return false;
                }

                command = makeCommand(Ryu, action);
                command();
                commandStack.push(command);
            }

            var cancalRyuFn = function(ary) {
                var timer = null,
                    ary = ary || [],
                    loop = function() {
                        timer && clearTimeout(timer);
                        var berCommand = ary.pop();
                        berCommand();
                        ary.length && (timer = setTimeout(loop, 1000));
                    };
                loop();
            }

            replayBtn.onclick = function() {
                            // var ps = [];
                            // commandStack.forEach(function(fn, index) {
                            // 	ps.push(new Promise((resolve, reject) => {
                            // 		setTimeout(() => {
                            // 			fn();
                            // 			resolve();
                            // 		}, index * 1000);
                            // 	}));
                            // })

                            // Promise.all(ps).then(() => {
                            // 	console.log('over');
                            // })
                commandStack.forEach(function(fn, index) {
                    new Promise((resolve, reject) => {
                        setTimeout(() => {
                            fn();
                            resolve();
                        }, index * 1000);
                    })
                })
            }

            cancalOpts.onclick = function() {
                cancalRyuFn(commandStack)
            }*/

        // 命令队列
        // 将小球的运动封装成命令对象，将他们放入一个命令队列中
        // 使用发布-订阅模式来通知队列
        var btn8 = document.querySelector('#btn8');
        var issuer = {
            commandList: [],
            isStart: false,
            listen: function(fn) {
                if (!fn) return false;
                this.commandList.push(fn)
            },

            triggerOne: function() {
                if (!this.commandList.length) return false;
                var fn = this.commandList.shift();
                fn();
            }
        }

        var DivCommand = function(receiver, endPos) {
            this.receiver = receiver;
            this.endPos = endPos;
        }

        DivCommand.prototype.execute = function(propertyName) {
            this.receiver.start(propertyName, this.endPos, 2000, 'Linear');
        }

        var move1 = function() {
            var ball = document.querySelector('.ball-1');
            var animate = new Animate(ball, issuer);
            var moveCommand = new DivCommand(animate, 270);
            issuer.listen(function() {
                moveCommand.execute('left')
            });
        }

        var move2 = function() {
            var ball = document.querySelector('.ball-1');
            var animate = new Animate(ball, issuer);
            var moveCommand = new DivCommand(animate, 540);
            issuer.listen(function() {
                moveCommand.execute('left')
            });
        }

        var move3 = function() {
            var ball = document.querySelector('.ball-1');
            var animate = new Animate(ball, issuer);
            var moveCommand = new DivCommand(animate, 360);
            issuer.listen(function() {
                moveCommand.execute('left')
            });
        }

        var move4 = function() {
            var ball = document.querySelector('.ball-1');
            var animate = new Animate(ball, issuer);
            var moveCommand = new DivCommand(animate, 120);
            issuer.listen(function() {
                moveCommand.execute('left')
            });
        }

        var move5 = function() {
            var ball = document.querySelector('.ball-1');
            var animate = new Animate(ball, issuer);
            var moveCommand = new DivCommand(animate, 0);
            issuer.listen(function() {
                moveCommand.execute('left')
            });
        }

        move1()
        move2()
        move3()
        move4()
        move5()

        btn8.onclick = function() {
            issuer.triggerOne();
        }
    })()
</script>
</body>
</html>